#pragma once
#include <iostream>
#include <sys/epoll.h>
#include "Log.hpp"
#include "Sock.hpp"
#include "Epoll.hpp"
#include <cassert>
#include <string>
#include <unistd.h>
#include <functional>

namespace lb_epoll
{
    const static int default_port = 8080; // 默认端口号
    const static int gnum = 64;           // 缓冲区大小

    // 只处理读取事件
    class EpollServer
    {
        using func_t = std::function<void(std::string)>; // 回调方法
    public:
        EpollServer(func_t Handler, const uint16_t &port = default_port) : _port(port), _HandlerRequest(Handler), _revs_num(gnum)
        {
            // 0.申请缓冲区空间
            _revs = new struct epoll_event[_revs_num];
            // 1.创建listensock
            _listensock = Sock::Socket();
            // bind
            Sock::Bind(_listensock, _port);
            // 监听
            Sock::Listen(_listensock);
            // 2.创建epoll模型
            _epfd = Epoll::CreatePoll();
            logMessage(DEBUG, "init success,listensock: %d,epfd: %d", _listensock, _epfd);
            // 3.将listensock添加到epoll
            if (!Epoll::CtlEpoll(_epfd, EPOLL_CTL_ADD, _listensock, EPOLLIN))
            {
                exit(6);
            }
            logMessage(DEBUG, "add listensock to epoll success!");
        }
        void Accept(int listensock)
        {
            std::string client_ip;
            uint16_t client_port;
            int sock = Sock::Accept(listensock,&client_ip,&client_port);
            if(sock<0)
            {
                logMessage(WARNING,"accept error!");
                return;
            }
            //将sock添加到epoll中，等待数据
            if(!Epoll::CtlEpoll(_epfd,EPOLL_CTL_ADD,sock,EPOLLIN))
            {
                return ;
            }
            logMessage(DEBUG,"add new sock : %d to epoll success",sock);
        }
        void Recver(int sock)
        {
            char  buffer[10240];
            ssize_t n =recv(sock,buffer,sizeof(buffer)-1,0);
            if(n>0)
            {
                buffer[n]=0;
                logMessage(DEBUG,"recv success!");
                _HandlerRequest(buffer);//调用回调函数去处理
            }
            else if(n==0) //对方关闭
            {
               //2.先在epoll中去掉sock
                bool res = Epoll::CtlEpoll(_epfd,EPOLL_CTL_DEL,sock,0);
                assert(res);
                (void)res;
                close(sock);
                logMessage(NORMAL,"client %d quit,me too...",sock);
            }
            else{//读取失败
                bool res = Epoll::CtlEpoll(_epfd,EPOLL_CTL_DEL,sock,0);
                assert(res);
                (void)res;
                close(sock);
                logMessage(WARNING,"client recv read error ,close error sock: ",sock);
            }
        }
        void HandlerEvents(int n)
        {
            assert(n > 0);
            for (int i = 0; i < n; i++)
            {
                uint32_t revents = _revs[i].events;
                int sock = _revs[i].data.fd;
                if (revents & EPOLLIN) // 输入事件就绪
                {
                    if (sock == _listensock)
                    {
                        // 获取到新连接
                        Accept(_listensock);
                    }
                    else
                    {
                        // 普通sock，读取事件就绪
                        Recver(sock);
                    }
                }
                if(revents & EPOLLOUT)//输出事件就绪
                {

                }
            }
        }
        void loopOnce(int timeout)
        {
            int n = Epoll::WaitEpoll(_epfd, _revs, _revs_num, timeout);
            switch (n)
            {
            case 0:
                logMessage(DEBUG, "time out...");
                break;
            case -1:
                logMessage(WARNING, "epoll wait error,%s", strerror(errno));
                break;
            default:
                logMessage(DEBUG, "epoll get a event!");
                HandlerEvents(n); // n:获得多少个就绪的sock
                break;
            }
        }
        void Start()
        {
            int timeout = 1000;
            while (true)
            {
                loopOnce(timeout);
            }
        }
        ~EpollServer()
        {
            if (_listensock >= 0)
                close(_listensock);
            if (_epfd >= 0)
                close(_epfd);
            if (_revs)
            {
                delete[] _revs;
            }
        }

    private:
        uint16_t _port;
        int _epfd; // epoll句柄
        int _listensock;
        struct epoll_event *_revs; // 就绪缓冲区
        int _revs_num;             // 缓冲区大小
        func_t _HandlerRequest;    // 回调响应函数
    };
}
